import java.util.ArrayList;
import java.util.concurrent.Semaphore;

public class ManejadorCajas {

	private static ArrayList<Semaphore> listaSemaforos;
	private static ArrayList<Thread> hilos;
	private static int tiempo;
	static Semaphore semHilos;

	public ManejadorCajas() {
		tiempo = 1;
		System.out.println("Tiempo actual: 1");
		Archivos.escribirArchivo("ArchivoSalida.txt", "Tiempo actual: 1 \n",
				true);
		ManejadorCajas.hilos = new ArrayList<Thread>();
		ManejadorCajas.listaSemaforos = new ArrayList<Semaphore>();
		ManejadorCajas.semHilos = new Semaphore(1);
	}

	public static int getTiempo() {
		return tiempo;
	}

	/***
	 * Registra los hilos que van a correr para poder ser utilizados luego
	 */
	public static void registrarse(Thread hilo) {
		try {
			semHilos.acquire();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		if (!hilos.contains(hilo)) {
			hilos.add(hilo);
			listaSemaforos.add(new Semaphore(0));
			if (hilo instanceof CajaRedDeCobranza) {
				((CajaRedDeCobranza) hilo).setOcupada(false);
			}
			if (hilo instanceof CajaBoleteria) {
				((CajaBoleteria) hilo).setOcupada(false);
			}
			if (hilo instanceof CajaDefault) {
				((CajaDefault) hilo).setOcupada(false);
			}
		}
		semHilos.release();
	}

	/***
	 * 
	 * Cuando el hilo ya ha sido registrado y desea correr se le da el permiso
	 */
	public static void correr(Thread hilo) throws InterruptedException {
		semHilos.acquire();
		if (hilos.contains(hilo)) {
			if (hilo instanceof CajaRedDeCobranza
					&& ((CajaRedDeCobranza) hilo).isOcupada() == false) {
				int indice = hilos.indexOf(hilo);
				Semaphore sem = listaSemaforos.get(indice);
				sem.release();
			}
			if (hilo instanceof CajaBoleteria
					&& ((CajaBoleteria) hilo).isOcupada() == false) {
				int indice = hilos.indexOf(hilo);
				Semaphore sem = listaSemaforos.get(indice);
				sem.release();
			}
			if (hilo instanceof CajaDefault
					&& ((CajaDefault) hilo).isOcupada() == false) {
				int indice = hilos.indexOf(hilo);
				Semaphore sem = listaSemaforos.get(indice);
				sem.release();
			}
		}
		semHilos.release();
	}

	/***
	 * 
	 * Una vez que el hilo ya ha corrido al mismo se lo pone a dormir
	 */
	public static void corri(Thread hilo) throws InterruptedException {
		semHilos.acquire();
		if (hilos.contains(hilo)) {
			int indice = hilos.indexOf(hilo);
			Semaphore sem = listaSemaforos.get(indice);
			if (hilo instanceof CajaRedDeCobranza) {
				((CajaRedDeCobranza) hilo).setOcupada(true);
				terminaronDeCorrer();
				sem.acquire();
			}
			if (hilo instanceof CajaBoleteria) {
				((CajaBoleteria) hilo).setOcupada(true);
				terminaronDeCorrer();
				sem.acquire();
			}
			if (hilo instanceof CajaDefault) {
				((CajaDefault) hilo).setOcupada(true);
				terminaronDeCorrer();
				sem.acquire();
			}
		}
	}

	/***
	 * 
	 * Una vez que todos los hilos terminaron de correr se incrementa el tiempo
	 * 
	 */
	public static void terminaronDeCorrer() throws InterruptedException {
		boolean terminaron = true;
		for (Thread hilo : hilos) {
			if (hilo instanceof CajaRedDeCobranza) {
				if (((CajaRedDeCobranza) hilo).isOcupada() == false) {
					terminaron = false;
					break;
				}
			}
			if (hilo instanceof CajaBoleteria) {
				if (((CajaBoleteria) hilo).isOcupada() == false) {
					terminaron = false;
					break;
				}
			}
			if (hilo instanceof CajaDefault) {
				if (((CajaDefault) hilo).isOcupada() == false) {
					terminaron = false;
					break;
				}
			}
		}

		if (terminaron == true) {
			tiempo++;
			// System.out.println("Tiempo actual: " + tiempo);
			Archivos.escribirArchivo("ArchivoSalida.txt", "Tiempo actual: "
					+ tiempo + "\n", true);
			for (Thread hilo : hilos) {
				if (hilo instanceof CajaRedDeCobranza) {
					((CajaRedDeCobranza) hilo).setOcupada(false);
				}
				if (hilo instanceof CajaBoleteria) {
					((CajaBoleteria) hilo).setOcupada(false);
				}
				if (hilo instanceof CajaDefault) {
					((CajaDefault) hilo).setOcupada(false);
				}
			}
			for (Semaphore sem : listaSemaforos) {
				if (sem != null) {
					sem.release();
				}
			}
		}
		semHilos.release();
	}

	/***
	 * 
	 * Una vez que terminaron de correr los hilos avisan para ser sacados de la
	 * cola de hilos
	 */
	public static void finalice(Thread hilo) {
		try {
			semHilos.acquire();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		if (hilos.contains(hilo)) {
			int indice = hilos.indexOf(hilo);
			hilos.remove(indice);
			listaSemaforos.remove(indice);
		}
		if (hilo instanceof CajaRedDeCobranza) {
			((CajaRedDeCobranza) hilo).setOcupada(false);
		}
		if (hilo instanceof CajaBoleteria) {
			((CajaBoleteria) hilo).setOcupada(false);
		}
		if (hilo instanceof CajaDefault) {
			((CajaDefault) hilo).setOcupada(false);
		}
		semHilos.release();
	}
}
